/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package tnviet.proj.jna.textgroup;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
/**
 *
 * @author Administrator
 */
public class MaskTextField extends JTextField
	implements DocumentListener, FocusListener, KeyListener
{
	private TextGroup parent;
	private String mask;
	private Color maskColor = TextGroup.DEFAULT_MASK_COLOR;
	private boolean displayPartialMask = TextGroup.DEFAULT_DISPLAY_PARTIAL_MASK;
	private boolean isFocusTraversable = true;
	private FieldValidator validator;
	private StringBuffer textBuffer = new StringBuffer();


	public MaskTextField(int size, String mask)
	{
		super(size);
		setMask( mask );

		if (mask.trim().length() == 0)
			setMask( null );

		getDocument().addDocumentListener( this );
		addFocusListener( this );
		addKeyListener( this );
	}

	/*
	**  Parent is set when this MaskTextField is part of a group
	*/
	public void setParent(TextGroup parent)
	{
		this.parent = parent;
	}

	/*
	**	Text displayed in the background of the component
	*/
	public void setMask(String mask)
	{
		this.mask = mask;
	}

	public String getMask()
	{
		return mask;
	}

	/*
	**  Methods to control the mask text color
	*/
	public void setMaskColor(Color color)
	{
		maskColor = color;
	}

	public Color getMaskColor()
	{
		if (parent != null)
			return parent.getMaskColor();
		else
			return maskColor;
	}

	/*
	**  Control how the background mask is rendered
	*/
	public void setDisplayPartialMask(boolean value)
	{
		displayPartialMask = value;
	}

	public boolean isDisplayPartialMask()
	{
		if (parent != null)
			return parent.isDisplayPartialMask();
		else
			return displayPartialMask;
	}

	/*
	**  Add class to perform simple validation of typed characters
	*/
	public void setValidator(FieldValidator validator)
	{
		this.validator = validator;
	}

	/*
	**
	*/
    @Override
	public boolean isFocusTraversable()
	{
		return isFocusTraversable;
	}

	public void setFocusTraversable(boolean value)
	{
		isFocusTraversable = value;
	}

	/*
	**  Override to add a mask as a background to the text field
	*/
    @Override
	public void paintComponent(Graphics g)
	{
		super.paintComponent(g);

		if (mask == null)
			return;

		int length = getDocument().getLength();

		//  Paint mask character in remaining text field space

		if (isDisplayPartialMask() && length < mask.length())
		{
			g.setColor( getMaskColor() );
			FontMetrics fm = getFontMetrics( getFont() );
			int y = getInsets().top + fm.getAscent();
			int x = getInsets().left + fm.stringWidth( getText() );
			g.drawString( mask.substring( length ), x, y );
			return;
		}

		//  Paint mask characters only when text field is empty

		if (!isDisplayPartialMask() && length == 0)
		{
			Dimension d = getSize();
			g.setColor( getMaskColor() );
			FontMetrics fm = getFontMetrics( getFont() );
			int y = getInsets().top + fm.getAscent();
			int x = getInsets().left + (int)((d.width - fm.stringWidth( mask )) / 2);
			g.drawString( mask, x, y );
			return;
		}

	}

	/*
	**  Override so that the default document is always a SizeDocument
	*/
    @Override
	protected Document createDefaultModel()
	{
		return new SizeDocument( getColumns() );
	}

	//  Implement DocumentListener
	//  Automatically tab when the text field becomes full

	public void insertUpdate(DocumentEvent e)
	{
		Document doc = (Document)e.getDocument();

		if (doc.getLength() == getColumns())
		{
			Object parent = getParent();

			if (parent instanceof TextGroup)
			{
				((TextGroup)parent).tab(this, TextGroup.TAB_NEXT);
			}
			else
				FocusManager.getCurrentManager().focusNextComponent( this );
		}
	}

	public void removeUpdate(DocumentEvent e) {}
	public void changedUpdate(DocumentEvent e) {}

	//  Implement FocusListener
	//  Select all the text when a text field gains focus

		public void focusGained(FocusEvent e)
		{
			JTextField textField = (JTextField)e.getSource();
			textField.selectAll();
			textField.setToolTipText( null );
		}

		public void focusLost(FocusEvent e) {}

	//  Implement KeyListener

	public void keyTyped(KeyEvent e)
	{
		//  The following keys are always valid

		switch ( (int)e.getKeyChar())
		{
			case KeyEvent.VK_BACK_SPACE:
			case KeyEvent.VK_ESCAPE:
			case KeyEvent.VK_TAB:
				return;
		}

		//  Invoke the validator to make sure the key is valid

		if (validator != null)
		{
			setToolTipText( null );
			String possibleText = getPossibleText( e );

			if (! validator.isValid( possibleText ) )
			{
//				Toolkit.getDefaultToolkit().beep();
				setToolTipText( validator.getMessage() );
				Component c = (Component)e.getSource();
				c.dispatchEvent( new KeyEvent (c, KeyEvent.KEY_PRESSED, 0, KeyEvent.CTRL_MASK, KeyEvent.VK_F1) );
				e.consume();
			}
		}
	}

	public void keyPressed(KeyEvent e) {}
	public void keyReleased(KeyEvent e) {}

	/*
	**  Get the possible text by:
	**  1) getting the current text,
	**  2) delete any selected text,
	**  3) insert typed character
	*/
	private String getPossibleText(KeyEvent e)
	{
		JTextField textField = (JTextField)e.getSource();

		textBuffer.setLength(0);
		textBuffer.append( textField.getText() );

		int start =  textField.getSelectionStart();
		int end = textField.getSelectionEnd();
		textBuffer.delete(start, end);

		textBuffer.insert(start, e.getKeyChar());

		return textBuffer.toString();
	}

	/*
	**  Control the number of characters that can be entered
	*/
	class SizeDocument extends PlainDocument
	{
		private int maximumFieldLength = 0;

		public SizeDocument(int maximumFieldLength)
		{
			this.maximumFieldLength = maximumFieldLength;
		}

		public void insertString(int offset, String text, AttributeSet a)
			throws BadLocationException
		{
			if (text == null)
				return;

			//  Make sure text does not exceed its maximum length

			if ( getLength() + text.length() > maximumFieldLength )
			{
				Toolkit.getDefaultToolkit().beep();
			}
			else
			{
				super.insertString(offset, text, a);
			}
		}
	}
}
